﻿/*
 * OpenDoPE Word Add-In
 * Copyright (C) 2010-2011  Plutext Pty Ltd
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 * 
 * For details, see http://www.gnu.org/licenses/gpl-2.0.html
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using NLog;

using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;


namespace OpenDoPE_Wed
{
    public partial class UserControlBindButtons : UserControl
    {

        static Logger log = LogManager.GetLogger("OpenDoPE_Wed");

        WedTaskPane taskPane;

        public UserControlBindButtons(WedTaskPane taskPane)
            //Word.ContentControl currentCC, XmlEditorControl xec)
        {
            this.taskPane = taskPane;

            //this.currentCC = currentCC;
            //this.xec = xec;

            InitializeComponent();


        }

        /// <summary>
        /// SetMapping not allowed for rich text content controls;
        /// consistent with spec.
        /// 
        /// </summary>
        /// <param name="currentCC"></param>
        /// <returns></returns>
        public bool ensurePlainText(Word.ContentControl currentCC)
        {

            if (currentCC.Type == Word.WdContentControlType.wdContentControlRichText)
            {
                DialogResult dr = MessageBox.Show("This control is a rich text one.  These can't be bound.  Convert to plain text?", "Convert Control?",  MessageBoxButtons.YesNo);

                if (dr.Equals(DialogResult.No))
                {
                    // Remove control and return
                    return false;
                }

                // Try to convert
                try
                {
                    currentCC.Type = Word.WdContentControlType.wdContentControlText;
                    return true;
                }
                catch (Exception e)
                {
                    // "Inappropriate range for applying this control type"
                    // if there are paragraphs..
                    Mbox.ShowSimpleMsgBoxError("Couldn't convert to plain text. (Does it contain paragraphs?)");
                    log.Error(e);
                    return false;
                }

            }
            else
            {
                return true;
            }

        }

        private void buttonApply_Click(object sender, EventArgs e)
        {
            log.Debug("bind clicked..");

            Word.ContentControl currentCC = taskPane.currentCC;
            XmlEditorControl xec = taskPane.xmlEditor;

            if (!xec.isWellFormed()) return;

            // Save the XML
            xec.commitChanges();


            // Now write the xpath 

            if (!xec.isInputOK())
            {
                return;
            }

            if (currentCC == null)
            {
                Mbox.ShowSimpleMsgBoxWarning("ERROR: Current content control is unknown.");
                log.Error("currentCC not set?!");
                return;
            }

            TagData td = new TagData(currentCC.Tag);
            String existingID = td.get("od:xpath");
            String allocatedID= xec.textBoxXPathID.Text.Trim();
            bool updateOtherControls = false;
            if (existingID != null && allocatedID.Equals(existingID))
            {
                // The ID hasn't changed; we silently reuse it
                updateOtherControls = true;
            }
            else
            {
                // They've typed another ID
                // Does it exist already?  
                if (XPathPartUtils.getByID(taskPane.xpathsPart, allocatedID) != null)
                {
                    // If so, overwrite that one, or choose again?
                    // Press OK to overwrite, or cancel to choose another ID
                    if (MessageBox.Show("This XPath for this ID will be updated. Press Cancel if you'd prefer to specify a different ID.", "ID exists", MessageBoxButtons.OKCancel) 
                            == DialogResult.Cancel)
                    {
                        return;
                    }
                    updateOtherControls = true;
                }
            }

            string prefixMappings = xec.getPrefixMappings();

            Word.XMLMapping bind = currentCC.XMLMapping;

            Office.CustomXMLPart cxp = taskPane.activeCxp;

            bool mappable = bind.SetMapping(xec.xpathTextBox.Text, prefixMappings, cxp);

            if (!mappable)
            {
                Mbox.ShowSimpleMsgBoxWarning("Your XPath does not return an element. The OpenDoPE pre-processor will attempt to evaluate it, but Word will never update the result. ");
                log.Debug(xec.xpathTextBox.Text + " does not return an element. Deleting...");
                bind.Delete();
            }
            
            // Question
            string questionID = null;
            if (taskPane.questions)
            {
                FormQuestion formQuestion = new FormQuestion(taskPane.questionsPart, xec.xpathTextBox.Text);
                formQuestion.ShowDialog();
                // TODO - handle cancel

                formQuestion.updateQuestionsPart(formQuestion.getQuestion());

                questionID = formQuestion.textBoxQID.Text;
                // TODO ensure questionID is an NCName
                formQuestion.Dispose();
            }

            // Also add to XPaths


            XPathPartUtils.updateXPathsPart(taskPane.xpathsPart,
                xec.xpathTextBox.Text,
                allocatedID,
                cxp.Id, prefixMappings, questionID);

            // Write tag
            td.remove("od:xpath");
            td.remove("od:repeat");
            td.remove("od:condition");
            td.set("od:xpath", xec.textBoxXPathID.Text.Trim() );
            currentCC.Tag = td.asQueryString();

            int count = 1;
            if (mappable && updateOtherControls)
            {
                count = SetMappingOnOtherSdts(allocatedID, xec.xpathTextBox.Text, prefixMappings, cxp);
                // At the very least that will setmapping on this control again, but that's OK
            }

            Mbox.ShowSimpleMsgBoxInfo("Bound " + count + " control(s)");
        }

        public int SetMappingOnOtherSdts(string xmlId, string xpath, string prefixmappings, Office.CustomXMLPart cxp)
        {
            int count = 0;
            foreach (Word.Range storyRange in Globals.ThisAddIn.Application.ActiveDocument.StoryRanges)
            {
                foreach (Word.ContentControl cc in storyRange.ContentControls)
                {
                    TagData td = new TagData(cc.Tag);
                    String existingID = td.get("od:xpath");

                    if (existingID != null
                        && existingID.Equals(xmlId)
                        && cc.XMLMapping.IsMapped) // not repeats or conditions
                    {
                        cc.XMLMapping.SetMapping(xpath, prefixmappings, cxp);
                        count++;
                    }
                }
            }
            return count;
        }


        private void buttonCancel_Click(object sender, EventArgs e)
        {

            Word.ContentControl currentCC = taskPane.currentCC;
            XmlEditorControl xec = taskPane.xmlEditor;

            if (currentCC == null)
            {
                log.Error("currentCC not set?!");
                return;
            }
            Word.XMLMapping bind = currentCC.XMLMapping;

            if (!bind.IsMapped)
            {
                Mbox.ShowSimpleMsgBoxInfo("This content control wasn't bound.");
                return;
            }

            bind.Delete();
            Mbox.ShowSimpleMsgBoxInfo("Bind deleted from this content control.");


        }
    }
}
